import { ref, h, inject, markRaw } from "vue";

export function createWebHashHistory() {
  function getInitialPath() {
    return window.location.hash.slice(1) || "/";
  }

  return {
    type: "hash",
    getInitialPath,
  };
}

export function createWebHistory() {
  function getInitialPath() {
    return window.location.pathname || "/";
  }

  return {
    type: "history",
    getInitialPath,
  };
}
export function createRouter(options) {
  const { history, routes } = options;
  const currentPath = ref(history.getInitialPath());

  window.addEventListener("hashchange", () => {
    currentPath.value = window.location.hash.slice(1) || "/";
  });

  const routerInstance = {
    install(app) {
      app.provide("router", routerInstance);
      app.component("RouterLink", RouterLink);
      app.component("RouterView", RouterView);
    },
    currentPath,
    routes,
    push(path) {
      window.location.hash = path;
      currentPath.value = path;
    },
  };

  return routerInstance;
}

const RouterLink = {
  props: {
    to: {
      type: String,
      required: true,
    },
  },
  setup(props, { slots }) {
    return () => {
      return h("a", { href: `#${props.to}` }, slots.default());
    };
  },
};

const RouterView = {
  setup() {
    const router = inject("router");
    return () => {
      const path = router.currentPath.value;
      const route = router.routes.find((r) => r.path === path);
      const component = route.component;

      if (typeof component === "function") {
        // 返回一个包装后的异步组件
        return h({
          setup() {
            const comp = ref(null); // 用 ref 来存储加载的组件
            const error = ref(null);

            component()
              .then((res) => {
                comp.value = markRaw(res.default); // 加载成功，更新 ref 的值
              })
              .catch((err) => {
                console.log(err);
                error.value = err;
              });

            // 返回一个渲染函数
            return () => {
              if (error.value) return h("div", "Component Load Failed");
              if (!comp.value) return h("div", "Loading...");
              return h(comp.value); // 当 comp.value 变化时，这里会自动重新渲染
            };
          },
        });
      }
      // 如果是普通组件 (对象)
      return h(component);
    };
  },
};
